fix(memory): Fix memory leak for audio events when pausing the game#2731
fix(memory): Fix memory leak for audio events when pausing the game#2731Caball009 wants to merge 2 commits into
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Include/Common/AudioRequest.h | Adds releasePendingEvent() declaration to AudioRequest, enabling explicit ownership transfer of m_pendingEvent. |
| Core/GameEngine/Source/Common/Audio/AudioRequest.cpp | Implements the destructor fix (deletes m_pendingEvent when m_usePendingEvent is true) and adds releasePendingEvent() which clears the ownership flag and returns the raw pointer. |
| Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h | Updates playAudioEvent signature from AudioEventRTS* to AudioRequest* to allow ownership transfer inside the function. |
| Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp | Refactors playAudioEvent to accept the full AudioRequest* and call releasePendingEvent() at each point where ownership is transferred to PlayingAudio::m_audioEventRTS, covering all three sound-type branches (stream, 3D, 2D). |
Sequence Diagram
sequenceDiagram
participant PA as pauseAudio()
participant AR as AudioRequest
participant MAM as MilesAudioManager
participant PlayingAudio
note over PA,AR: Pause path (leak fixed)
PA->>AR: deleteInstance(req) [AR_Play requests]
AR->>AR: ~AudioRequest(): if(m_usePendingEvent) delete m_pendingEvent
note over MAM,PlayingAudio: Normal play path (ownership transfer)
MAM->>MAM: "processRequest(req) -> playAudioEvent(req)"
MAM->>AR: "req->releasePendingEvent()"
AR-->>MAM: "AudioEventRTS* (m_usePendingEvent=false, m_pendingEvent=nullptr)"
MAM->>PlayingAudio: "audio->m_audioEventRTS = releasedEvent"
MAM->>AR: "deleteInstance(req) [m_usePendingEvent=false, no double-free]"
PlayingAudio->>PlayingAudio: "releasePlayingAudio() -> releaseAudioEventRTS() -> delete event"
Reviews (4): Last reviewed commit: "Implemented 'releasePendingEvent' member..." | Re-trigger Greptile
057637e to
977bd8b
Compare
977bd8b to
afb337c
Compare
|
Rebased to include the fix for the CI Replay checker. |
There was a problem hiding this comment.
On second look, it is not great that m_usePendingEvent is still true now, because other functions assume m_pendingEvent is non-null when m_usePendingEvent is true.
Can do
m_usePendingEvent = req->m_pendingEvent != nullptr;Or maybe better, we pass AudioRequest *& to playAudioEvent and add new function:
AudioEventRTS *AudioRequest::releasePendingEvent()
{
if (m_usePendingEvent)
{
m_usePendingEvent = false;
AudioEventRTS *event = m_pendingEvent;
m_pendingEvent = nullptr;
return event;
}
return nullptr;
}Then do:
audio->m_audioEventRTS = req->releasePendingEvent();This assignment then takes care of everything.
There was a problem hiding this comment.
playAudioEvent( AudioRequest* req ) should be fine, though, right?
9e09418 to
08f2330
Compare
|
|
||
| AudioEventRTS* AudioRequest::releasePendingEvent() | ||
| { | ||
| DEBUG_ASSERTCRASH(m_usePendingEvent && m_pendingEvent, ("audio request was expected to contain valid audio event")); |
There was a problem hiding this comment.
This assert is a bit late because it would have already crashed before in MilesAudioManager::playAudioEvent if m_pendingEvent was 0.
I suggest move this assert to the begin of MilesAudioManager::playAudioEvent
|
|
||
| // Put this on here, so that the audio event RTS will be cleaned up regardless. | ||
| audio->m_audioEventRTS = event; | ||
| audio->m_audioEventRTS = req->releasePendingEvent(); |
There was a problem hiding this comment.
You could also write audio->m_audioEventRTS = event = req->releasePendingEvent(); and just keep using event everywhere.
Pausing the game leaks audio events that were in the audio request container at the time. This PR fixes that.
This code is called to get rid of some of the audio requests when pausing the game:
GeneralsGameCode/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp
Lines 587 to 601 in 2219f63
AudioRequest::m_pendingEventcan be an owning raw pointer, though, which the destructor ofAudioRequestshould delete when needed. It currently doesn't, which is why the leak happens.GeneralsGameCode/Core/GameEngine/Include/Common/AudioRequest.h
Line 51 in 2219f63
There's one exception where the ownership of the audio event is taken away from the audio request:
GeneralsGameCode/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp
Line 2238 in 2219f63